"use strict";

var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _objectSpread6 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2"));
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
var _react = require("react");
var logger = _interopRequireWildcard(require("../logger"));
var _useHelpers2 = _interopRequireDefault(require("./uses/useHelpers"));
var _useFind2 = _interopRequireDefault(require("./uses/useFind"));
/**
 * 不能修改的关键字
 */
var KEYWORDS = ['uniqueKey', 'levelKey', 'childrenKey', 'parentKey'];
/**
 * 树结构数据管理
 * @see http://10.145.11.75:8080/gui/szzj-hooks/#/guide/use-tree
 * @todo immer.js 只读返回，以免节点引用变更
 * @todo 接口表现上，key 和 node 统一
 * @param treeNodes 树节点列表
 * @param options options.uniqueKey 唯一键属性名
 * @param options options.levelKey 层级属性名，从 1 开始计数
 * @param options options.beginingLevel 层级从几开始计算，默认为 1
 * @param options options.parentKey 父节点属性名
 * @param options options.childrenKey 子节点属性名
 * @param options options.onAdd 节点新增时回调
 * @param options options.onInsertAfter 节点后插入回调
 * @param options options.onReplace 节点替换时回调，不能替换 uniqueKey、levelKey、parentKey、childrenKey 等关键属性
 * @param options options.onRemove 节点删除时回调
 */
var useTree = function useTree(initialTreeNodes, options) {
  var _ref = options !== null && options !== void 0 ? options : {},
    _ref$uniqueKey = _ref.uniqueKey,
    uniqueKey = _ref$uniqueKey === void 0 ? 'key' : _ref$uniqueKey,
    _ref$levelKey = _ref.levelKey,
    levelKey = _ref$levelKey === void 0 ? 'level' : _ref$levelKey,
    _ref$beginingLevel = _ref.beginingLevel,
    beginingLevel = _ref$beginingLevel === void 0 ? 1 : _ref$beginingLevel,
    _ref$childrenKey = _ref.childrenKey,
    childrenKey = _ref$childrenKey === void 0 ? 'children' : _ref$childrenKey,
    _ref$parentKey = _ref.parentKey,
    parentKey = _ref$parentKey === void 0 ? 'parentKey' : _ref$parentKey,
    onAdd = _ref.onAdd,
    onInsertAfter = _ref.onInsertAfter,
    onReplace = _ref.onReplace,
    onRemove = _ref.onRemove;
  var _useHelpers = (0, _useHelpers2.default)(options),
    forEach = _useHelpers.forEach,
    map = _useHelpers.map,
    filter = _useHelpers.filter,
    toArray = _useHelpers.toArray,
    toMap = _useHelpers.toMap;
  // 内部表示，不同引用，附着 parentKey 及 level
  var _useState = (0, _react.useState)([]),
    _useState2 = (0, _slicedToArray2.default)(_useState, 2),
    treeNodes = _useState2[0],
    setTreeNodes = _useState2[1];
  /** 遍历添加 levelKey, parentKey */
  (0, _react.useEffect)(function () {
    if (!(initialTreeNodes === null || initialTreeNodes === void 0 ? void 0 : initialTreeNodes.length)) return;
    var treeNodesAttachedParent = map(initialTreeNodes, function (node, _ref2) {
      var _objectSpread2;
      var level = _ref2.level,
        parent = _ref2.parent;
      return (0, _objectSpread6.default)((0, _objectSpread6.default)({}, node), {}, (_objectSpread2 = {}, (0, _defineProperty2.default)(_objectSpread2, levelKey, level + beginingLevel), (0, _defineProperty2.default)(_objectSpread2, parentKey, parent === null || parent === void 0 ? void 0 : parent[uniqueKey]), _objectSpread2));
    });
    setTreeNodes(treeNodesAttachedParent);
  }, [initialTreeNodes, beginingLevel, map]);
  var _useFind = (0, _useFind2.default)(treeNodes, options),
    treeNodeMap = _useFind.treeNodeMap,
    hasNode = _useFind.hasNode,
    findNode = _useFind.findNode,
    findParent = _useFind.findParent,
    findAncestorNodes = _useFind.findAncestorNodes,
    findSiblingsIncludeSelf = _useFind.findSiblingsIncludeSelf,
    findPosterityNodesByKey = _useFind.findPosterityNodesByKey,
    findIndex = _useFind.findIndex;
  var _changeNodes = (0, _react.useCallback)(function (nodes, parent) {
    var newTreeNodes = [];
    if (parent) {
      // @ts-ignore
      parent[childrenKey] = nodes.length ? (0, _toConsumableArray2.default)(nodes) : undefined;
      newTreeNodes = (0, _toConsumableArray2.default)(treeNodes);
    } else {
      newTreeNodes = (0, _toConsumableArray2.default)(nodes);
    }
    setTreeNodes(newTreeNodes);
  }, [treeNodes]);
  /** 节点交换 */
  var exchange = (0, _react.useCallback)(function (sourceNode, targetNode) {
    if (!hasNode(sourceNode[uniqueKey]) || !hasNode(targetNode[uniqueKey])) {
      logger.fail('cannot find node，please check');
      return;
    }
    var parent = findParent(sourceNode);
    var siblings = findSiblingsIncludeSelf(sourceNode);
    var newSiblings = siblings.map(function (sibling) {
      if (sibling[uniqueKey] === sourceNode[uniqueKey]) return targetNode;else if (sibling[uniqueKey] === targetNode[uniqueKey]) return sourceNode;
      return sibling;
    });
    _changeNodes(newSiblings, parent);
  }, [hasNode, uniqueKey, findParent, findSiblingsIncludeSelf, _changeNodes]);
  /** 节点上移 */
  var up = (0, _react.useCallback)(function (sourceNode) {
    if (!hasNode(sourceNode[uniqueKey])) {
      logger.fail('cannot find node，please check');
      return;
    }
    var siblings = findSiblingsIncludeSelf(sourceNode);
    var index = findIndex(sourceNode);
    if (index > 0) {
      exchange(sourceNode, siblings[index - 1]);
    } else {
      logger.fail('index should more then 0');
    }
  }, [hasNode, uniqueKey, findSiblingsIncludeSelf, findIndex, exchange]);
  /** 节点后移 */
  var down = (0, _react.useCallback)(function (sourceNode) {
    if (!hasNode(sourceNode[uniqueKey])) {
      logger.fail('cannot find node，please check');
      return;
    }
    var siblings = findSiblingsIncludeSelf(sourceNode);
    var index = findIndex(sourceNode);
    if (index < siblings.length - 1) {
      exchange(sourceNode, siblings[index + 1]);
    } else {
      logger.fail("index should less then (nodes's length - 1)");
    }
  }, [hasNode, uniqueKey, findSiblingsIncludeSelf, findIndex, exchange]);
  /** 指定节点后插入 */
  var insertAfter = (0, _react.useCallback)(function (sourceNode, targetKey) {
    var _parent$level;
    if (findNode(sourceNode[uniqueKey])) {
      logger.fail('you should not insert node with same key!');
      return;
    }
    var targetNode = findNode(targetKey);
    var parent = findParent(targetNode);
    var subTreeMap = toMap([sourceNode], {
      beginingLevel: ((_parent$level = parent === null || parent === void 0 ? void 0 : parent.level) !== null && _parent$level !== void 0 ? _parent$level : 0) + 1
    });
    var newNode = (0, _objectSpread6.default)((0, _objectSpread6.default)({}, subTreeMap[sourceNode[uniqueKey]]), {}, (0, _defineProperty2.default)({}, parentKey, parent === null || parent === void 0 ? void 0 : parent[uniqueKey]));
    var siblings = findSiblingsIncludeSelf(targetNode);
    var index = findIndex(targetNode);
    siblings.splice(index + 1, 0, newNode);
    _changeNodes(siblings, parent);
    onInsertAfter === null || onInsertAfter === void 0 ? void 0 : onInsertAfter(sourceNode, targetNode);
  }, [findNode, findParent, toMap, findSiblingsIncludeSelf, findIndex, _changeNodes, onInsertAfter]);
  /** 父节点下作为尾部节点插入，支持子树 */
  var append = (0, _react.useCallback)(function (sourceNode, pKey) {
    var _parent$level2, _parent$childrenKey;
    if (findNode(sourceNode[uniqueKey])) {
      logger.fail('you should not insert node with same key!');
      return;
    }
    var parent = pKey ? findNode(pKey) : undefined;
    var subTreeMap = toMap([sourceNode], {
      beginingLevel: ((_parent$level2 = parent === null || parent === void 0 ? void 0 : parent.level) !== null && _parent$level2 !== void 0 ? _parent$level2 : 0) + 1
    });
    var newNode = (0, _objectSpread6.default)((0, _objectSpread6.default)({}, subTreeMap[sourceNode[uniqueKey]]), {}, (0, _defineProperty2.default)({}, parentKey, parent === null || parent === void 0 ? void 0 : parent[uniqueKey]));
    var siblings = parent ? [].concat((0, _toConsumableArray2.default)((_parent$childrenKey = parent[childrenKey]) !== null && _parent$childrenKey !== void 0 ? _parent$childrenKey : []), [newNode]) : [].concat((0, _toConsumableArray2.default)(treeNodes), [newNode]);
    _changeNodes(siblings, parent);
    onAdd === null || onAdd === void 0 ? void 0 : onAdd(newNode, parent);
  }, [findNode, toMap, treeNodes, _changeNodes, onAdd]);
  /** 父节点下作为头部节点插入，支持子树 */
  var prepend = (0, _react.useCallback)(function (sourceNode, pKey) {
    var _parent$level3, _parent$childrenKey2;
    if (findNode(sourceNode[uniqueKey])) {
      logger.fail('you should not insert node with same key!');
      return;
    }
    var parent = pKey ? findNode(pKey) : undefined;
    var subTreeMap = toMap([sourceNode], {
      beginingLevel: ((_parent$level3 = parent === null || parent === void 0 ? void 0 : parent.level) !== null && _parent$level3 !== void 0 ? _parent$level3 : 0) + 1
    });
    var newNode = (0, _objectSpread6.default)((0, _objectSpread6.default)({}, subTreeMap[sourceNode[uniqueKey]]), {}, (0, _defineProperty2.default)({}, parentKey, parent === null || parent === void 0 ? void 0 : parent[uniqueKey]));
    var siblings = parent ? [newNode].concat((0, _toConsumableArray2.default)((_parent$childrenKey2 = parent[childrenKey]) !== null && _parent$childrenKey2 !== void 0 ? _parent$childrenKey2 : [])) : [newNode].concat((0, _toConsumableArray2.default)(treeNodes));
    _changeNodes(siblings, parent);
    onAdd === null || onAdd === void 0 ? void 0 : onAdd(newNode, parent);
  }, [findNode, toMap, treeNodes, _changeNodes, onAdd]);
  /** 替换节点 */
  var replace = (0, _react.useCallback)(function (likeNode) {
    var _parent$childrenKey3;
    var targetNode = findNode(likeNode[uniqueKey]);
    var parent = findParent(targetNode);
    // 1. 构建新的节点
    var newNode = (0, _objectSpread6.default)({}, targetNode);
    Object.keys(likeNode).forEach(function (key) {
      if (!KEYWORDS.includes(key)) {
        // @ts-ignore
        newNode[key] = likeNode[key];
      }
    });
    var siblings = ((_parent$childrenKey3 = parent === null || parent === void 0 ? void 0 : parent[childrenKey]) !== null && _parent$childrenKey3 !== void 0 ? _parent$childrenKey3 : treeNodes).map(function (childNode) {
      if (childNode[uniqueKey] === newNode[uniqueKey]) return newNode;
      return childNode;
    });
    _changeNodes(siblings, parent);
    onReplace === null || onReplace === void 0 ? void 0 : onReplace(newNode);
  }, [findNode, findParent, treeNodes, _changeNodes, onReplace]);
  /** 删除节点 */
  var remove = (0, _react.useCallback)(function (key) {
    var _parent$childrenKey4;
    var sourceNode = findNode(key);
    var parent = findParent(sourceNode);
    var removedNodes = [];
    var removedKeys = [];
    forEach([sourceNode], function (node) {
      removedNodes.push(node);
      removedKeys.push(node[uniqueKey]);
    });
    var siblings = ((_parent$childrenKey4 = parent === null || parent === void 0 ? void 0 : parent[childrenKey]) !== null && _parent$childrenKey4 !== void 0 ? _parent$childrenKey4 : treeNodes).filter(function (node) {
      return node[uniqueKey] !== sourceNode[uniqueKey];
    });
    _changeNodes(siblings, parent);
    onRemove === null || onRemove === void 0 ? void 0 : onRemove(removedKeys, removedNodes, sourceNode);
  }, [findNode, findParent, forEach, treeNodes, _changeNodes, onRemove]);
  return {
    /** 节点树 */
    treeNodes: treeNodes,
    /** 节点映射 */
    treeNodeMap: treeNodeMap,
    /** 遍历节点 */
    forEach: forEach,
    /** 遍历转换节点 */
    map: map,
    /** 过滤节点 */
    filter: filter,
    /** 扁平化成一维数组 */
    toArray: toArray,
    /** 扁平化成键值对映射 */
    toMap: toMap,
    /** 通过 key 获取节点 */
    findNode: findNode,
    /** 获取父节点 */
    findParent: findParent,
    /** 获取祖先节点 */
    findAncestorNodes: findAncestorNodes,
    /** 获取同一层级元素，包含自身 */
    findSiblingsIncludeSelf: findSiblingsIncludeSelf,
    /** 数组形式获取子孙节点列表 */
    findPosterityNodesByKey: findPosterityNodesByKey,
    /** 找到节点在同一层级元素中的索引 */
    findIndex: findIndex,
    /** 交换节点 */
    exchange: exchange,
    /** 节点上移 */
    up: up,
    /** 节点下移 */
    down: down,
    /** 在指定节点后插入 */
    insertAfter: insertAfter,
    /** 在指定节点下方插入，作为最后一个子节点 */
    append: append,
    /** 在指定节点下方插入，作为第一个子节点 */
    prepend: prepend,
    /** 替换节点 */
    replace: replace,
    /** 移除节点 */
    remove: remove
  };
};
var _default = useTree;
exports.default = _default;